怎么给文件生成MD5 您所在的位置:网站首页 word md5码 怎么给文件生成MD5

怎么给文件生成MD5

2023-09-10 06:11| 来源: 网络整理| 查看: 265

MD5 的核心是通过算法把任意长度的原始数据映射成128 bit 的数据。把一串数据经过处理,得到另一个固定长度的数据。是一种Hash算法,全称为 消息摘要算法版本5(Message Digest Algorithm 5)。

不同原始数据会有不同的 MD5 值。 所以不同的文件MD5的值也不一样。

一般在上传文件的场景里,会根据MD5实现续传、秒传的功能。

本文简单写下怎么生成 MD5,这里用到插件spark-md5。

TL;DR 怕麻烦,10M以内生成MD5,直接用法一就行 怕麻烦,30M以内生成MD5,直接用法二就行 再大一点,用法三吧 但法三可以用在以上所有场景 法一:生成文件的 MD5

生成文件的 MD5,简单思路如下:

创建 FileReader 实例,读文件 读完之后,成功状态下,直接使用SparkMD5.hashBinary。

具体代码在文末。

缺陷

这种方式,当文件越大的时候,生成 md5 的速度也就越慢,比如 40M 的文件可能需要 1s 才生成 md5。当页面还有其他的交互的时候,将会堵塞其他交互,导致页面假死状态。

举个例子:加个按钮,写个点击事件。选择文件之后,立即点击按钮,会发现,当文件越大的时候,弹框的速度越来越迟钝。

测试线程堵塞 upload.onchange = async (e) => { const file = e.target.files[0]; console.time("timeCreateMd5"); const md5 = await createFileMd5(file); console.log(file.size); // 会打印timeCreateMd5: 959.31396484375 ms console.timeEnd("timeCreateMd5"); }; 法二:在worker中生成md5

所以我们使用 web-worker 在 worker 线程计算 hash,这样用户仍可以在主界面正常的交互,不会引起堵塞。 当前页面的修改,如下:

新增在worker里执行的hash.js文件如下:

self.importScripts("https://unpkg.com/[email protected]/spark-md5.min.js"); // 生成文件 hash self.onmessage = async e => { const file = e.data const md5 = await createFileMd5(file) self.postMessage(md5); }; function createFileMd5(file){ // ... // 同之前的,但以下需要修改,增加self的前缀 isSuccess ? resolve(self.SparkMD5.hashBinary(result)) : reject(new Error("读取出错了")); }

到这,其实虽然生成大文件的md5耗费时间长,但起码不会堵塞页面主线程了。

也有缺陷

可以看到计算md5是将整个文件读完才看到,这样当文件过大是极其耗内存的。所以需要分片读取生成md5。

法三:将文件分片生成md5

仔细看spark-md5,其实作者也是推荐分片读取,类似nodejs里面的流一样,这样不需要占据大量内存。

先将文件,按照一定大小分块chunk,这边直接使用File.slice了。

然后将chunks传给另一个线程计算md5,这边大文件可能需要进度条,所以有一个进度,按需求使用。

附注:代码 代码:生成小文件的 MD5 Document const upload = document.querySelector("#upload"); upload.onchange = async (e) => { const file = e.target.files[0]; const md5 = await createFileMd5(file); console.log(md5); }; function createFileMd5(file) { return new Promise((resolve, reject) => { // 创建FileReader实例 const fileReader = new FileReader(); // 开始读文件 fileReader.readAsBinaryString(file); // 文件读完之后,触发load事件 fileReader.onload = (e) => { // e.target就是fileReader实例 console.log(e.target); // result是fileReader读到的部分 const result = e.target.result; // 如果读到的长度和文件长度一致,则读取成功 const isSuccess = file.size === result.length; // 读取成功,则生成MD5,扔出去。失败就报错 isSuccess ? resolve(SparkMD5.hashBinary(result)) : reject(new Error("读取出错了")); }; // 读取过程中出错也直接报错 fileReader.onerror = () => reject(new Error("读取出错了")); }); } 代码:在worker中生成md5 Document 测试线程堵塞 const upload = document.querySelector("#upload"); upload.onchange = async (e) => { const file = e.target.files[0]; console.time("timeCreateMd5"); const md5 = await createFileMd5InWorker(file); console.log(file.size); console.timeEnd("timeCreateMd5"); }; // 生成文件 md5(web-worker) function createFileMd5InWorker(file) { return new Promise((resolve) => { // 新建worker线程,执行hash.js const worker = new Worker("./hash.js"); // 给线程传file worker.postMessage(file); // 当线程传消息的时候,接受消息 worker.onmessage = (e) => { const md5 = e.data; md5 && resolve(md5) }; }); } // hash.js self.importScripts("https://unpkg.com/[email protected]/spark-md5.min.js"); // 生成文件 md5 self.onmessage = async e => { const file = e.data const md5 = await createFileMd5(file) self.postMessage(md5); self.close() }; function createFileMd5(file) { return new Promise((resolve, reject) => { // 创建FileReader实例 const fileReader = new FileReader(); // 开始读文件 fileReader.readAsBinaryString(file); // 文件读完之后,触发load事件 fileReader.onload = (e) => { // e.target就是fileReader实例,这里用this也是指fileReader实例 console.log(e.target); // result是fileReader读到的部分 const result = e.target.result; // 如果读到的长度和文件长度一致,则读取成功 const isSuccess = file.size === result.length; // 读取成功,则生成MD5,扔出去。失败就报错 isSuccess ? resolve(self.SparkMD5.hashBinary(result)) : reject(new Error("读取出错了")); }; // 读取过程中出错也直接报错 fileReader.onerror = () => reject(new Error("读取出错了")); }); } 代码:分片读取生成md5 Document 测试线程堵塞 const upload = document.querySelector("#upload"); upload.onchange = async (e) => { const file = e.target.files[0]; const chunks = createFileChunk(file) console.time("timeCreateMd5"); // 这里注意放chunks const {md5} = await createFileMd5InWorker(chunks); console.log(file.size); console.timeEnd("timeCreateMd5"); }; // 生成文件切片 function createFileChunk(file, size = 4 * 1024 * 1024) { let chunks = []; let cur = 0; while (cur < file.size) { chunks.push(file.slice(cur, cur + size)); cur += size; } return chunks; } // 生成文件 hash(web-worker) function createFileMd5InWorker(fileChunks) { return new Promise((resolve) => { const worker = new Worker("./hash.js"); worker.postMessage({ fileChunks }); worker.onmessage = (e) => { // 这边加了进度条 这里的进度条,看需要显示 const { percentage, hash } = e.data; console.log(percentage) // 计算出hash之后,扔出去 hash &&resolve(hash); }; }); } // 直接copy的 https://juejin.cn/post/6844904046436843527#heading-17 self.importScripts("./js/lib/spark-md5.min.js"); // 导入脚本 // 生成文件 hash self.onmessage = e => { const { fileChunks } = e.data; console.log(fileChunks) // const { fileChunks } = e.data; const spark = new self.SparkMD5.ArrayBuffer(); let percentage = 0; let count = 0; const loadNext = index => { const reader = new FileReader(); reader.readAsArrayBuffer(fileChunks[index]); reader.onload = e => { count++; spark.append(e.target.result); if (count === fileChunks.length) { self.postMessage({ percentage: 100, hash: spark.end() }); self.close(); } else { percentage += 100 / fileChunks.length; self.postMessage({ percentage }); loadNext(count); } }; }; loadNext(0); }; 引用 字节跳动面试官:请你实现一个大文件上传和断点续传 js 实现 input file 转换成 blob 和 byte 字节流 三分钟学习md5


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有